package com.test.learnkotlin

/*
Android Studio 查看源码编译后的字节码(java/kotlin)
https://blog.csdn.net/guangdeshishe/article/details/116094602

一文吃透 Kotlin 中眼花缭乱的函数家族
https://mp.weixin.qq.com/s/KsVbVBLAAMe9dNW5Us09vw
 */
fun main() {

    val result = generateAnswerString(3, 1)
    println("result = $result")

    val stringLength = stringLengthFunc("android")
    println("stringLength = $stringLength")

    val classTemp = Temp()
    val stringMapper = classTemp.stringMapper("android", stringLengthFunc)
    println("stringMapper = $stringMapper")

    //当然，如果不实例化匿名函数也是可以的，在使用函数的时候将 lambda 表达式直接传入，等待调用。
    val stringMapper2 = classTemp.stringMapper("android", { input -> input.length })
    println("stringMapper2 = $stringMapper2")

    //如果传入的 lambda 表达式是最后一个参数的话，可单独拎出，更加简洁。
    val stringMapper3 = classTemp.stringMapper("android") { input -> input.length }
    println("stringMapper3 = $stringMapper3")

    //如果高阶函数只有一个函数参数的话，调用的时候可直接省略圆括号。
    val stringMapperNew = classTemp.stringMapperNew { input -> input.length }
    println("stringMapperNew = $stringMapperNew")


    //具名函数参数
    //
    //除了传入匿名函数的方法体或引用，还可以传入普通函数的名称作为参数。写法稍稍不同，::functionName 的形式。
    val stringMapper4 = classTemp.stringMapper("android", ::stringLengthInner)
    println("stringMapper4 = $stringMapper4")


}

fun generateAnswerString(count: Int, countThreshold: Int): String {
    return if (count > countThreshold) "I have the answer." else "The answer eludes me." //反编译之后发现其采用的三元运算符的写法。
}

/*
    Kotlin 中并不要求函数都拥有名称，只声明其必要的输入类型、输出类型以及表达式即可完成函数的定义。

    比如：String 即为输入参数类型，Int 为输出类型，花括号内为 lambda 表达式：

    it 是隐式参数名称，也可任意拟定，比如这里用 input 指定。如果不需要参数的话也可以省略
    如果有不需要的参数一般用下划线_取代其名称
    input.length 为计算逻辑以及表达式返回值

 */
val stringLengthFunc: (String) -> Int = { input -> input.length }

/*
    高阶函数
    高阶函数是将函数用作参数或返回值的函数。支持高阶函数是 Kotlin 函数式编程的一大特性
 */
class Temp {
    //如下的 stringMapper 即为高阶函数，mapper 即为函数参数的引用名称。
    fun stringMapper(input: String, mapper: (String) -> Int): Int {
        return mapper(input)
    }

    //如果高阶函数只有一个函数参数的话，调用的时候可直接省略圆括号。
    val temp = "ddd"
    fun stringMapperNew(mapper: (String) -> Int): Int {
        return mapper(temp)
    }
}

/*
具名函数参数

除了传入匿名函数的方法体或引用，还可以传入普通函数的名称作为参数。写法稍稍不同，::functionName 的形式。

 */

fun stringLengthInner(input: String): Int = input.length


/*
函数作为返回值

如果函数并非想要知道处理结果，只想获得处理方法的话，可以将返回值定义成匿名函数的规格，并在 return 里写上匿名函数的实现。
 */

fun stringMapperFunction(input: String): (String) -> Int {
    return {
        val newString = input.substring(
            input.indexOf("start")
        )

        newString.length
    }
}


